﻿namespace Fiddler
{
    using System;
    using System.Collections.Generic;
    using System.Threading;

    internal static class ScheduledTasks
    {
        private static Dictionary<string, jobItem> _dictSchedule = new Dictionary<string, jobItem>();
        private static ReaderWriterLock _RWLockDict = new ReaderWriterLock();
        private static Timer _timerInternal = null;
        private const int CONST_MIN_RESOLUTION = 15;

        internal static bool CancelWork(string sTaskName)
        {
            bool flag;
            try
            {
                _RWLockDict.AcquireWriterLock(-1);
                flag = _dictSchedule.Remove(sTaskName);
            }
            finally
            {
                _RWLockDict.ReleaseWriterLock();
            }
            return flag;
        }

        private static void doWork(object objState)
        {
            List<KeyValuePair<string, jobItem>> list = null;
            try
            {
                _RWLockDict.AcquireReaderLock(-1);
                ulong tickCount = Utilities.GetTickCount();
                foreach (KeyValuePair<string, jobItem> pair in _dictSchedule)
                {
                    if (tickCount > pair.Value._ulRunAfter)
                    {
                        pair.Value._ulRunAfter = ulong.MaxValue;
                        if (list == null)
                        {
                            list = new List<KeyValuePair<string, jobItem>>();
                        }
                        list.Add(pair);
                    }
                }
                if (list == null)
                {
                    return;
                }
                LockCookie lockCookie = _RWLockDict.UpgradeToWriterLock(-1);
                try
                {
                    foreach (KeyValuePair<string, jobItem> pair2 in list)
                    {
                        _dictSchedule.Remove(pair2.Key);
                    }
                    if ((_dictSchedule.Count < 1) && (_timerInternal != null))
                    {
                        _timerInternal.Dispose();
                        _timerInternal = null;
                    }
                }
                finally
                {
                    _RWLockDict.DowngradeFromWriterLock(ref lockCookie);
                }
            }
            finally
            {
                _RWLockDict.ReleaseReaderLock();
            }
            foreach (KeyValuePair<string, jobItem> pair3 in list)
            {
                try
                {
                    pair3.Value._oJob();
                    continue;
                }
                catch (Exception)
                {
                    continue;
                }
            }
        }

        internal static bool ScheduleWork(string sTaskName, uint iMaxDelay, SimpleEventHandler workFunction)
        {
            try
            {
                _RWLockDict.AcquireReaderLock(-1);
                if (_dictSchedule.ContainsKey(sTaskName))
                {
                    return false;
                }
            }
            finally
            {
                _RWLockDict.ReleaseReaderLock();
            }
            jobItem item = new jobItem(workFunction, iMaxDelay);
            try
            {
                _RWLockDict.AcquireWriterLock(-1);
                if (_dictSchedule.ContainsKey(sTaskName))
                {
                    return false;
                }
                _dictSchedule.Add(sTaskName, item);
                if (_timerInternal == null)
                {
                    _timerInternal = new Timer(new TimerCallback(ScheduledTasks.doWork), null, 15, 15);
                }
            }
            finally
            {
                _RWLockDict.ReleaseWriterLock();
            }
            return true;
        }

        private class jobItem
        {
            public SimpleEventHandler _oJob;
            public ulong _ulRunAfter;

            public jobItem(SimpleEventHandler oJob, uint iMaxDelay)
            {
                this._ulRunAfter = iMaxDelay + Utilities.GetTickCount();
                this._oJob = oJob;
            }
        }
    }
}

